package com.foreveross.util.cfg;

import org.apache.commons.lang3.StringUtils;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.Serializable;
import java.util.HashMap;
import java.util.Map;
import java.util.Properties;

public class ConfigContainer implements Serializable {
    protected static Logger logger = LoggerFactory.getLogger(ConfigContainer.class);

    private final static String ALL_FILE = "ALL_FILE";
    /**
     *
     */
    private static final long serialVersionUID = -6872344806680589604L;
    /**
     * 配置文件的字段/值缓存对象
     * Map<String, Map<String, String>> 第一个String为文件名,后面的Map为读取的属性文件键值对
     */
    private Map<String, Map<String, String>> propertyCache = new HashMap<String, Map<String, String>>();
    /**
     * 加载器缓存
     * Map<String, ConfigLocalLoader> 第一个String为存储文件名
     */
    private Map<String, ConfigLocalLoader> loaderCache = new HashMap<String, ConfigLocalLoader>();

    private static ConfigContainer _ConfigContainer = null;

    public static ConfigContainer getInstance() {
        if (_ConfigContainer == null) _ConfigContainer = new ConfigContainer();
        return _ConfigContainer;
    }

    public synchronized String get(String key, String file) {
        String result = null;
        if (ALL_FILE.equalsIgnoreCase(file)) {
            for (String f : propertyCache.keySet()) {
                //以防死循环
                if (ALL_FILE.equalsIgnoreCase(f)) break;
                result = get(key, f);
                if (StringUtils.isNotBlank(result)) break;
            }
        }
        //没有该文件，则加载
        if (!loaderCache.containsKey(file)) {
            if (logger.isDebugEnabled()) {
                logger.error("未找到文件file=" + file);
            }
            throw new ConfigLocalLoadException(String.format("没有找到文件[%s]对应加载类!", file));
        } else {
            if (!loaderCache.get(file).isHasLoad()) {
                loaderCache.get(file).load();
            }
        }
        if (propertyCache.containsKey(file))
            return propertyCache.get(file).get(key);
        return result;
    }

    /**
     * 注册到容器中
     *
     * @param file
     * @param property
     */
    public synchronized void register(Class<? extends ConfigLocalLoader> _clazz) {
        try {
            ConfigLocalLoader loader = _clazz.newInstance();
            loaderCache.put(loader.getFileName(), loader);
        } catch (Exception e) {
            //logger.error(e);
            throw new ConfigLocalLoadException(e);
        }
    }

    /**
     * @param clazzPath 指定的类必须继承于ConfigLocalLoader
     * @Description: TODO
     * @author luofangyi
     * @date 2014-8-29 上午10:37:40
     */
    public synchronized void register(String clazzPath) {
        try {
            if (Class.forName(clazzPath).newInstance() instanceof ConfigLocalLoader) {
                ConfigLocalLoader loader = (ConfigLocalLoader) Class.forName(clazzPath).newInstance();
                loaderCache.put(loader.getFileName(), loader);
            } else {
                logger.error(String.format("%s必须继承于ConfigLocalLoader", clazzPath));
            }
        } catch (Exception e) {
            //logger.error(e);
        }
    }

    /**
     * 注册到容器中
     *
     * @param file
     * @param property
     */
    public synchronized void registerCache(String file, Map<String, String> property) {
        evict(file);

        propertyCache.put(file, property);
    }

    /**
     * 注册到容器中
     *
     * @param file
     * @param property
     */
    public synchronized void registerCache(String file, Properties property) {
        evict(file);

        Map<String, String> prop = new HashMap<String, String>();

        for (Object key : property.keySet()) {
            prop.put(key.toString(), property.get(key).toString());
        }
        propertyCache.put(file, prop);
    }

    /**
     * 从容器中移除
     *
     * @param file
     */
    public synchronized void evict(Object file) {
        if (propertyCache.containsKey(file)) {
            propertyCache.remove(file);
            loaderCache.remove(file);
        }
    }

    public synchronized void destroy() {
        propertyCache.clear();
        loaderCache.clear();
        propertyCache = null;
        loaderCache = null;
        _ConfigContainer = null;
    }


    public Object get(Object arg0) {
        return get(arg0.toString(), ALL_FILE);
    }


    public void put(Object arg0, Object arg1) {
        if (arg1 instanceof Properties) {
            this.registerCache(arg0.toString(), (Properties) arg1);
        } else if (arg1 instanceof Map) {
            this.registerCache(arg0.toString(), (Map<String, String>) arg1);
        }
    }
}
